package com.hilin.base.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hilin.base.conf.ServerConfig;
import com.hilin.base.dao.mapper.IOrgMapper;
import com.hilin.common.common.BaseController;
import com.hilin.common.common.ReturnCode;
import com.hilin.common.util.AssertUtils;
import com.hilin.common.util.IdUtils;
import com.hilin.common.util.RandomUtils;
import com.hilin.entity.po.OrgInfoPo;
import com.hilin.entity.vo.OrgInfoVo;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
public class OrgService {

    @Autowired
    private IOrgMapper iOrgMapper;

    @Autowired
    private ServerConfig serverConfig;

    @SneakyThrows
    public List<OrgInfoPo> childList(Long orgId) {
        orgCanOperator(orgId);
        QueryWrapper<OrgInfoPo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(OrgInfoPo::getOrgPid, orgId);
        return Optional.ofNullable(iOrgMapper.selectList(queryWrapper)).orElse(new ArrayList<>());
    }

    public OrgInfoPo detail(Long orgId) {
        OrgInfoPo orgInfo = iOrgMapper.selectById(orgId);
        AssertUtils.isNotEmpty(orgInfo, ReturnCode.DATA_NOT_EXIST.respMsg("机构不存在"));
        if (!orgId.equals(BaseController.getSign().getOrgId())) {
            AssertUtils.isRex(!ObjectUtils.isEmpty(orgInfo.getOrgNodes()) && orgInfo.getOrgNodes().contains(String.format(OrgInfoPo.ORG_NODE_NAME, BaseController.getSign().getOrgId())),
                    ReturnCode.AUTH_NO_OPERATOR.respMsg("无权查询该机构"));
        }
        return orgInfo;
    }

    public OrgInfoPo create(OrgInfoPo orgInfo) {
        orgInfo.setOrgId(IdUtils.DEFAULT.gen());
        orgInfo.setOrgSecret(RandomUtils.genRandomStr(serverConfig.getSecretLen()));
        OrgInfoPo pOrgInfo = iOrgMapper.selectById(orgInfo.getOrgPid());
        AssertUtils.isNotEmpty(pOrgInfo, ReturnCode.DATA_NOT_EXIST.respMsg("父机构不存在"));
        orgCanOperator(orgInfo.getOrgPid());
        orgInfo.setOrgNodes(pOrgInfo.getOrgNodes() + String.format(OrgInfoPo.ORG_NODE_NAME, pOrgInfo.getOrgId()));
        iOrgMapper.insert(orgInfo);
        return orgInfo;
    }

    public void edit(Long orgId, String orgName) {
        orgCanOperator(orgId);
        iOrgMapper.updateById(OrgInfoPo.builder()
                .orgId(orgId)
                .orgName(orgName)
                .build());
    }

    public void delete(Long orgId) {
        OrgInfoPo orgInfoPo = iOrgMapper.selectById(orgId);
        // 机构不存在，则认为已删除，返回成功
        AssertUtils.isNotEmpty(orgInfoPo, ReturnCode.SUCCESS.resp());
        orgCanOperator(orgInfoPo);
        iOrgMapper.updateById(OrgInfoPo.builder()
                .build());
    }


    /**
     * 判断是否有操作指定机构的权限
     *
     * @param orgId
     * @return
     */
    private void orgCanOperator(Long orgId) {
        // 操作token所在单位，直接放行
        if (BaseController.getSign().getOrgId().equals(orgId)) {
            return;
        }
        OrgInfoPo orgInfoPo = iOrgMapper.selectById(orgId);
        AssertUtils.isNotEmpty(orgInfoPo, ReturnCode.DATA_NOT_EXIST.respMsg("机构不存在:" + orgId));
        orgCanOperator(orgInfoPo);
    }

    /**
     * 判断是否有操作指定机构的权限
     */
    private void orgCanOperator(OrgInfoPo orgInfo) {
        String nodes = orgInfo.getOrgNodes();
        // 只有超管才没有上级节点，因此不认证
        if (ObjectUtils.isEmpty(nodes)) {
            return;
        }
        boolean result = orgInfo.getOrgNodes().contains(String.format(OrgInfoPo.ORG_NODE_NAME, BaseController.getSign().getOrgId()));
        AssertUtils.isNotEmpty(result, ReturnCode.AUTH_NO_OPERATOR.respMsg("没有操作该机构的权限"));
    }

    public String resetSecret(Long orgId, boolean invalidOldToken) {
        orgCanOperator(orgId);
        String secret = RandomUtils.genRandomStr(serverConfig.getSecretLen());
        iOrgMapper.updateById(OrgInfoPo.builder()
                .orgId(orgId)
                .orgSecret(secret)
                .build());
        return secret;
    }

    @SneakyThrows
    public List<OrgInfoVo> childTreeList(Long orgId) {
        orgCanOperator(orgId);
        OrgInfoPo queryPo = OrgInfoPo.builder()
                .build().like(OrgInfoPo.builder()
                        .orgNodes(String.format(OrgInfoPo.ORG_NODE_NAME, orgId))
                        .build());
        List<OrgInfoPo> orgInfoList = iOrgMapper.selectList(queryPo.getQueryWrapper());
        return null;
    }

    @SneakyThrows
    public IPage<OrgInfoPo> childAllList(Long orgId, String name, String address, Integer pagesize, Integer pagenum) {
        orgCanOperator(orgId);
        OrgInfoPo orgInfo = OrgInfoPo.builder()
                .build().like(OrgInfoPo.builder()
                        .orgNodes(String.format(OrgInfoPo.ORG_NODE_NAME, orgId))
                        .orgName(name)
                        .orgAddress(address)
                        .build());
        return iOrgMapper.selectPage(new Page<>(pagenum, pagesize), orgInfo.getQueryWrapper());
    }
}
